Inner class(내부 클래스)
inner class는 말 그대로 “클래스 내부에 선언한 클래스” 이다.
이는 외부 클래스와 밀접한 관련이 있거나, 다른 외부 클래스와 협력할 일이 없는 경우에 사용한다.
class ABC{
class In{
static class SIn{
}
}
public void abc(){
class Local{
}
}
}
내부클래스에는
인스턴스 내부 클래스, 정적 내부 클래스, 지역 내부 클래스, 익명 내부 클래스가 있다.
-Instance inner class
내부 클래스는 인스턴스 변수를 선언할 때와 같은 위치에 선언하며,
외부 클래스 내부에서만 생성하여 사용하는 객체를 선언할 때 쓴다.
(다른 외부 클래스에서 사용할 일이 없는 경우 내부 인스턴스 클래스로 정의)
InnerTest.java
package innerclass;
class OutClass {
private int num=10;
private static int sNum=20;
private InClass inClass;
public OutClass() {
inClass=new InClass();
}
class InClass{
int inNum=100;
void inTest() {
System.out.println("OutCLass num= "+num+"(외부클라스의 인스턴스 변수)");
System.out.println("OutCLass sNum= "+sNum+"(외부 클래스의 정적 변수)");
}
}
public void usingClass() {
inClass.inTest();
}
}
public class InnerTest{
public static void main(String[] args) {
OutClass outClass=new OutClass();
System.out.println("외부 클래스 이용하여 내부 클라스 기능 호출");
outClass.usingClass();
}
}
외부 클래스가 선언된 이후에 내부 클래스가 선언되어야 한다.
따라서 클래스의 생성과 상관없이 사용할 수 있는 정적 변수는 인스턴스 내부 클래스에서 선언할 수 없다.
private 이 아닌 내부클래스의 경우 외부 클래스가 아닌 다른 클래스에서도
아래와 같이 내부 클래스를 생성할 수 있다.
OutClass outClass=new OutClass();
OutCLass.InClass inClass=OutClass.new InClass();
따라서 어떤 클라스 내부에서만 사용할 목적이라면 내부 클래스를
private으로 선언해야 한다.
-static inner class
내부 클래스가 외부 클래스 생성과 무관하게 사용할 수 있어야 하고,
정적 변수도 사용할 수 있어야 한다면 정적 내부 클래스를 사용하면 된다.
InnerTest.java
package innerclass;
class OutClass {
private int num=10;
private static int sNum=20;
static class InStaticClass{
int inNum=10;
static int sInNum=20;
void inTest() {
System.out.println("InStaticClass inNum= "+inNum+"(내부 클래스의 인스턴스 변수 사용)");
System.out.println("InStaticClass sInNum= "+sInNum+"(내부 클래스의 정적 변수 사용)");
System.out.println("OutClass sNum= "+sNum+"(외부 클래스의 정적 변수 사용");
}
static void sTest() {
System.out.println("OutClass sNum= "+sNum+"(외부 클래스의 정적 변수 사용");
System.out.println("InStaticClass sInNum= "+sInNum+"(내부 클래스의 정적 변수 사용)");
}
}
}
public class InnerTest{
public static void main(String[] args) {
OutClass.InStaticClass sInClass=new OutClass.InStaticClass();
System.out.println("정적 내부 클래스 일반 메서드 호출");
sInClass.inTest();
System.out.println();
System.out.println("정적 내부클래스의 정적 메서드 호출");
OutClass.InStaticClass.sTest();
}
}
정적 내부 클래스는 외부 클래스를 생성하지 않고 바로 정적 내부 클래스 생성 가능하다.
정적 내부
클래스 메서드 |
변수 유형 |
사용 가능 여부 |
일반
메서드
void inTest() |
외부 클래스의 인스턴스 변수(num) |
X |
외부 클래스의 정적 변수(sNum) |
O |
정적 내부 클래스의 인스턴스 변수(inNum) |
O |
정적 내부 클래스의 정적 변수(sInNum) |
O |
정적
메서드
static void aTest() |
외부 클래스의 인스턴스 변수(num) |
X |
외부 클래스의 정적 변수(sNum) |
O |
정적 내부 클래스의 인스턴스 변수(inNum) |
X |
정적 내부 클래스의 정적 변수(sInNum) |
O |
정적 내부 클래스는 외부 클래스를 생성하지 않고도 내부 클래스 자료형으로 바로 선언하여 생성할 수 있다.
OutClass.InStaticClass sInClass=new OutClass.InStaticClass();
또한 정적 내부 클래스에 선언한 메서드나 변수가 private이 아닌 경우 다른 클래스에서 바로 사용할 수 있다.
OutClass.InstaticClass.sTest();
-Local inner class
지역 내부 클래스는 지역 변수처럼 메서드 내부에 클래스를 정의하여 사용하는 것을 말한다.
LocalInnerTest.java
package innerclass;
class Outer{
int outNum=100;
static int sNum=200;
Runnable getRunnable(int i) {
int num=100;
class MyRunnable implements Runnable{
int localNum=100;
@Override
public void run() {
System.out.println("i ="+i);
System.out.println("num= "+num);
System.out.println("localNum= "+localNum);
System.out.println("outNum= "+outNum+"(외부 클래스 인스턴스 변수");
System.out.println("Outer.sNum= "+Outer.sNum+"(외부 클래스 정적 변수)");
}
}
return new MyRunnable();
}
}
public class LocalInnerTest {
public static void main(String[] args) {
Outer out=new Outer();
Runnable runner=out.getRunnable(10);
runner.run();
}
}
지역 내부 클래스에서는 지역 변수와 매개변수가 상수로 바뀌므로 변경할 수 없다.
java 7 이전에는 지역 내부 클라스는 상수만을 처리할 수 있었다.
하지만 java 8부터는 자동으로 컴파일 할 때 final 예약어가 추가 된다.
-Anonymous inner class
익명 클래스는 클래스 이름을 사용하지 않는 클래스이다.
아래의 코드는 이전의 LocalInnerTest.java의 MyRunnalbe(int i) 메서드를
익명 클래스로 표현한 코드이다.
package innerclass;
class Outer2{
Runnable getRunnable(int i) {
int num=100;
return new Runnable() {
@Override
public void run() {
System.out.println(i);
System.out.println(num);
}
};
}
Runnable runner=new Runnable() {
@Override
public void run() {
System.out.println("Runnable이 구현한 익명 클래스 변수");
}
};
}
public class AnonymousInnerTest {
public static void main(String[] args) {
Outer2 out=new Outer2();
Runnable runnerable=out.getRunnable(10);
runnerable.run();
out.runner.run();
}
}
익명 내부 클래스는 예전에 자바 UI에서 이벤트를 처리하는데 많이 사용하였다.
현재는 안드로이드 프로그래밍에서 위젯의 이벤트를 처리하는 핸들러를 구현할 때 사용한다.
아래 코드는 버튼을 눌렀을 때 “hello” 메세지를 출려하는 코드이다.
(버튼을 누르면 발생하는 이벤트 핸들러는 new View.OnCLickListener() 이다.
botton1.setOnClickListener=new View.OnClickListener(){
public boolean onClick(View v){
Toast.maekText(getBaseContext(),"hello",Toast.LENGTH_LONG).show();
return treu;
}
};
종류 |
구현 위치 |
사용할 수 있는
외부 클래스 변수 |
생성 방법 |
인스턴스 내부 클래스 |
외부 클래스 멤버 변수와 동일 |
외부 인스턴스 변수
외부 전역 변수 |
외부 클래스를 먼저 만든
후 내부 클래스 생성 |
정적 내부 클래스 |
외부 클래스 멤버 변수와 동일 |
외부 전역 변수 |
외부 클래스와 무관하게 생성 |
지역 내부 클래스 |
메서드 내부에 구현 |
외부 인스턴스 변수
외부 전역 변수 |
메서드를 호출할 때 생성 |
익명 내부 클래스 |
메서드 내부에 구현
변수에 대입하여 직접 구현 |
외부 인스턴스 변수
외부 전역 변수 |
메서드를 호출할 때 생성되거나,
인터페이스 타입변수에 대입할
때 new 예약어를 통해 생성 |